package com.iot08.admin.service;

import com.aliyun.tea.utils.StringUtils;
import com.iot08.admin.enums.PayOrderTypeEnum;
import com.iot08.admin.enums.PayStatusEnum;
import com.iot08.admin.service.page.PageVO;
import com.iot08.admin.service.page.PageableImpl;
import com.iot08.common.entity.app.Account;
import com.iot08.common.entity.app.PayOrderInfo;
import com.iot08.common.response.Response;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.DateUtil;
import com.iot08.common.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.ConvertOperators;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.addFields;


/**
 * @author cwj
 * @description
 * @date 2024/12/29 11:48
 **/
@Slf4j
@Service
public class PayOrderInfoService extends BaseService<PayOrderInfo> {

    @Resource
    private AccountService accountService;
    
    /**
     * @description 更新支付订单状态为退款状态
     * @author cwj
     * @param [orderId]
     * @return void
     * @date @time 2025/2/8 11:05
     **/
    public void updatePayOrderRefundStatus(String orderId,Integer orderStatus, Integer paymentStatus) {
        Update update = new Update();
        update.set("orderStatus",orderStatus);
        update.set("paymentStatus",paymentStatus);
        update.set("updateTime",new Date());
        this.updateById(new ObjectId(orderId),update);
    }

    /**
     * @description 分页查询支付订单列表
     * @author cwj
     * @param [page, startTime, endTime, payType]
     * @return org.springframework.data.domain.Page<com.iot08.common.entity.app.PayOrderInfo>
     * @date @time 2025/2/12 10:43
     **/
    public Page<PayOrderInfo> list(PageVO page,String startTime, String endTime,String transactionId,String phoneNum,
                                   String payType,Integer orderStatus,Integer orderType,Integer productType) {

        PageableImpl pageable = new PageableImpl();
        page.setSort(Sort.by(Sort.Order.desc("createTime")));
        pageable.setPage(page);

        Criteria criteria = new Criteria();
        if (StringUtil.isNotBlank(page.getSearchValue())) {
            criteria.and("_id").is(page.getSearchValue());
        }
        if(!StringUtils.isEmpty(transactionId)) {
            criteria.and("transactionId").is(transactionId);
        }
        if(!StringUtils.isEmpty(phoneNum)) {
            Account account = accountService.findOne(new Query(Criteria.where("phone").is(phoneNum)).limit(1));
            String openid = "";
            if(ObjectUtils.isNotEmpty(account)) {
               openid = account.getId();
            }
            criteria.and("openid").is(openid);
        }
        if(ObjectUtils.isNotEmpty(orderStatus)) {
            criteria.and("orderStatus").is(orderStatus);
        }
        if(ObjectUtils.isNotEmpty(orderType)) {
            criteria.and("orderType").is(orderType);
        }
        if(ObjectUtils.isNotEmpty(productType)) {
            criteria.and("productType").is(productType);
        }
        try {
            if(!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true)).
                        lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            } else if(!StringUtils.isEmpty(startTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true));
            } else if(!StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            }
        } catch (Exception e) {
            log.error("查询支付订单出现异常，异常信息为：{}",e.getMessage());
        }
        if(!StringUtils.isEmpty(payType)) {
            criteria.and("paymentMethod").is(payType);
        }
        Query query = new Query().addCriteria(criteria);
        long count = this.count(query);
        page.setTotalResult((int) count);
        List<PayOrderInfo> list = this.find(query.with(pageable));
        return  new PageImpl<PayOrderInfo>(list, pageable, count);
    }


    /**
     * @description 按条件统计
     * @author cwj
     * @param [id, startTime, endTime, transactionId, payType, orderType, productType]
     * @return java.lang.String
     * @date @time 2025/5/15 11:19
     **/
    public String queryPayTotalByParam(String id,String startTime, String endTime,String transactionId,
                                       String payType,Integer orderType,Integer productType){
        Criteria criteria = new Criteria();
        criteria.and("orderStatus").is(1);
        if (!StringUtils.isEmpty(id)) {
            criteria.and("_id").is(id);
        }
        if(!StringUtils.isEmpty(transactionId)) {
            criteria.and("transactionId").is(transactionId);
        }
        if(ObjectUtils.isNotEmpty(orderType)) {
            criteria.and("orderType").is(orderType);
        }
        if(ObjectUtils.isNotEmpty(productType)) {
            criteria.and("productType").is(productType);
        }
        try {
            if(!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true)).
                        lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            } else if(!StringUtils.isEmpty(startTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true));
            } else if(!StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            }
        } catch (Exception e) {
            log.error("查询支付订单出现异常，异常信息为：{}",e.getMessage());
        }
        if(!StringUtils.isEmpty(payType)) {
            criteria.and("paymentMethod").is(payType);
        }
        BigDecimal payTotal = new BigDecimal(0);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                addFields().addField("payAmountDecimal")
                        .withValue(ConvertOperators.ToDecimal.toDecimal("$payAmount"))
                        .build(),
                Aggregation.group()
                        .sum("payAmountDecimal").as("payTotal")
        );
        AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, "pay_order_info", Document.class);
        Document result = results.getUniqueMappedResult();
        if(ObjectUtils.isNotEmpty(result) && ObjectUtils.isNotEmpty(result.get("payTotal"))) {
            payTotal = new BigDecimal(result.get("payTotal").toString());
        }
        return payTotal.toString();
    }


    /**
     * @description
     * @author cwj
     * @param [outTradeNo, transactionId, paymentTime, realPayment, totalAmount, realReceiptAmount, orderStatus, paymentStatus, remark]
     * @return void
     * @date @time 2025/4/18 17:47
     **/
    public void updatePayOrderInfo(String outTradeNo, String transactionId, String paymentTime, BigDecimal realPayment, BigDecimal totalAmount,
                                   BigDecimal realReceiptAmount, Integer orderStatus, Integer paymentStatus, String remark) {
        Update update = new Update();
        if(!StringUtils.isEmpty(transactionId)){
            update.set("transactionId",transactionId);
        }
        if(ObjectUtils.isNotEmpty(orderStatus)){
            update.set("orderStatus",orderStatus);
        }
        if(!StringUtils.isEmpty(paymentTime)){
            update.set("paymentTime",paymentTime);
        }
        if(ObjectUtils.isNotEmpty(paymentStatus)){
            update.set("paymentStatus",paymentStatus);
        }
        if(ObjectUtils.isNotEmpty(totalAmount)){
            update.set("payAmout",totalAmount);
        }
        //用户实际支付金额，支付宝或微信支付补贴的，商家入账仍是支付金额
        if(ObjectUtils.isNotEmpty(realPayment)){
            update.set("realPayAmount",realPayment);
        }
        //商家实收金额
        if(ObjectUtils.isNotEmpty(realReceiptAmount)){
            update.set("realReceiptAmount",realReceiptAmount);
        }

        if(!StringUtils.isEmpty(remark)){
            update.set("remark",realPayment);
        }
        update.set("updateTime",new Date());
        this.updateById(new ObjectId(outTradeNo),update);
    }

    /**
     * @description 查询支付状态为0或1的且tranactionId不为空的苹果支付订单信息
     * @author cwj
     * @param []
     * @return java.util.List<com.iot08.common.entity.app.PayOrderInfo>
     * @date @time 2025/2/26 11:31
     **/
    public List<PayOrderInfo> queryApplePayOrderInfo() {
        Query query = new Query();
        Date curDate = new Date();
        // 使用 Calendar 类来操作日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curDate);
        // 将日期减去三天
        calendar.add(Calendar.DAY_OF_MONTH, -3);
        // 获取三天前的时间
        Date threeDaysAgo = calendar.getTime();
        query.addCriteria(Criteria.where("paymentMethod").is("applePay").
                and("transactionId").nin(null, "").
                and("paymentStatus").in(0,1).
                and("createTime").gte(threeDaysAgo).lte(curDate));
        return this.find(query);
    }

    /**
     * @description
     * @author cwj
     * @param [startTime, endTime, transactionId, payType, orderStatus]
     * @return com.iot08.common.response.Response<java.lang.Object>
     * @date @time 2025/4/18 17:22
     **/
    public void importData(String id,String startTime, String endTime, String transactionId, String payType, Integer orderStatus,Integer orderType,Integer productType,HttpServletResponse response){
        try {
            Criteria criteria = new Criteria();
            if (StringUtil.isNotBlank(id)) {
                criteria.and("_id").is(id);
            }
            if(!StringUtils.isEmpty(transactionId)) {
                criteria.and("transactionId").is(transactionId);
            }
            if(ObjectUtils.isNotEmpty(orderStatus)) {
                criteria.and("orderStatus").is(orderStatus);
            }
            if(ObjectUtils.isNotEmpty(orderType)) {
                criteria.and("orderType").is(orderType);
            }
            if(ObjectUtils.isNotEmpty(productType)) {
                criteria.and("productType").is(productType);
            }

            if(!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true)).
                        lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            } else if(!StringUtils.isEmpty(startTime)) {
                criteria.and("createTimestamp").gte(DateUtil.convertStrToTimeStamp(startTime,DateUtil.FORMAT_4,true));
            } else if(!StringUtils.isEmpty(endTime)) {
                criteria.and("createTimestamp").lte(DateUtil.convertStrToTimeStamp(endTime,DateUtil.FORMAT_4,false));
            }
            /*if(!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
                criteria.and("createTime").gte(DateUtil.convertStrToDate(startTime,DateUtil.FORMAT_4,true))
                        .lte(DateUtil.convertStrToDate(endTime,DateUtil.FORMAT_4,false));
            } else if(!StringUtils.isEmpty(startTime)) {
                criteria.and("createTime").gte(DateUtil.convertStrToDate(startTime,DateUtil.FORMAT_4,true));
            } else if(!StringUtils.isEmpty(endTime)) {
                criteria.and("createTime").lte(DateUtil.convertStrToDate(endTime,DateUtil.FORMAT_4,false));
            }*/
            if(!StringUtils.isEmpty(payType)) {
                criteria.and("paymentMethod").is(payType);
            }
            Query query = new Query().addCriteria(criteria);
            List<PayOrderInfo> list = this.find(query.with(Sort.by(Sort.Order.desc("createTime"))));
            //导出查询数据
            exportLargeData(list,response);
        } catch (Exception e) {
            log.error("导出支付订单出现异常，异常信息为：{}",e.getMessage());
        }
    }

    /**
     * @description 导出数据
     * @author cwj
     * @param [payOrderInfos, response]
     * @return void
     * @date @time 2025/4/18 17:58
     **/
    public void exportLargeData(List<PayOrderInfo> payOrderInfos, HttpServletResponse response) throws Exception {
        // 创建流式工作簿，窗口大小为100（表示只保留100行在内存）
        SXSSFWorkbook workbook = new SXSSFWorkbook(100);
        Sheet sheet = workbook.createSheet("支付订单");
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("商户订单号");
        headerRow.createCell(1).setCellValue("用户id");
        headerRow.createCell(2).setCellValue("支付订单号");
        headerRow.createCell(3).setCellValue("支付状态");
        headerRow.createCell(4).setCellValue("购买类型");
        headerRow.createCell(5).setCellValue("支付方式");
        headerRow.createCell(6).setCellValue("支付金额");
        headerRow.createCell(7).setCellValue("币种");
        headerRow.createCell(8).setCellValue("下单时间");
        headerRow.createCell(9).setCellValue("订单创建时间");
        for (int i = 0; i < payOrderInfos.size(); i++) {
            PayOrderInfo payOrderInfo = payOrderInfos.get(i);
            Row row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(payOrderInfo.getId());
            row.createCell(1).setCellValue(payOrderInfo.getOpenid());
            row.createCell(2).setCellValue(payOrderInfo.getTransactionId());
            row.createCell(3).setCellValue(ObjectUtils.isNotEmpty(payOrderInfo.getOrderStatus())?PayStatusEnum.getKeyByValue(payOrderInfo.getOrderStatus()):"");
            row.createCell(4).setCellValue(ObjectUtils.isEmpty(payOrderInfo.getOrderType())?"会员": PayOrderTypeEnum.getKeyByValue(payOrderInfo.getOrderType()));
            row.createCell(5).setCellValue(payOrderInfo.getPaymentMethod());
            row.createCell(6).setCellValue(ObjectUtils.isNotEmpty(payOrderInfo.getPayAmount())?payOrderInfo.getPayAmount().toString():"");
            row.createCell(7).setCellValue(payOrderInfo.getCurrency());
            row.createCell(8).setCellValue(payOrderInfo.getOrderTime());
            row.createCell(9).setCellValue(ObjectUtils.isEmpty(payOrderInfo.getCreateTime())?"":DateUtil.dateToStr(payOrderInfo.getCreateTime(),DateUtil.FORMAT_1));
        }
        // 设置导出
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=" +
                URLEncoder.encode("支付订单.xlsx", "UTF-8"));
        workbook.write(response.getOutputStream());
        // 清理临时文件
        workbook.dispose();
        workbook.close();
    }

    /**
     * @description 根据id集合
     * @author cwj
     * @param [ids]
     * @return java.util.List<com.iot08.common.entity.app.PayOrderInfo>
     * @date @time 2025/5/1 10:23
     **/
    public List<PayOrderInfo> queryPayOrderInfoByIds(List<String> ids) {
        List<ObjectId> objectIdList = ids.stream()
                .filter(org.apache.commons.lang3.StringUtils::isNotEmpty)               // 过滤空字符串
                .map(ObjectId::new)                            // 转换为 ObjectId
                .collect(Collectors.toList());
        Query query = new Query(Criteria.where("_id").in(objectIdList));
        return this.find(query);
    }


    /**
     * @description 查询支付成功总金额
     * @author cwj
     * @param []
     * @return com.iot08.common.response.Response<java.lang.Object>
     * @date @time 2025/5/14 9:40
     **/
    public Response<Object> queryPayTotal(){
        Criteria criteria = new Criteria();
        BigDecimal payTotal = new BigDecimal(0);
        criteria.and("orderStatus").is(1);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                addFields().addField("payAmountDecimal")
                        .withValue(ConvertOperators.ToDecimal.toDecimal("$payAmount"))
                        .build(),
                Aggregation.group()
                        .sum("payAmountDecimal").as("payTotal")
        );
        AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, "pay_order_info", Document.class);
        Document result = results.getUniqueMappedResult();
        if(ObjectUtils.isNotEmpty(result) && ObjectUtils.isNotEmpty(result.get("payTotal"))) {
            payTotal = new BigDecimal(result.get("payTotal").toString());
        }
        Response res = Response.successResponse();
        res.setData(payTotal);
        return res;
    }
}
